import os
import sys
import logging
from logging.handlers import FileHandler
import threading

class CustomLogger:
    """
    A custom logger class for logging messages to console and/or file with different log levels.

    Args:
        logger_name (str): The name of the logger.
        console_level (int, optional): The log level for console logging. Defaults to logging.DEBUG.
        file_level (int, optional): The log level for file logging. Defaults to logging.DEBUG.
    """
    
    _local = threading.local()

    def __init__(self, logger_name='custom_logger', console_level=logging.DEBUG, file_level=logging.DEBUG):
        """
        Initialize a CustomLogger instance.

        Args:
            logger_name (str): The name of the logger.
            console_level (int, optional): The log level for console logging. Defaults to logging.DEBUG.
            file_level (int, optional): The log level for file logging. Defaults to logging.DEBUG.
        """
        self.logger_name = logger_name
        self.log_file = None
        self.logger = None
        self.console_level = console_level
        self.file_level = file_level

    def _init_logger(self):
        """
        Initialize the logger with console and file handlers.
        """
        self.logger = logging.getLogger(self.logger_name)
        self.logger.setLevel(logging.DEBUG)

        formatter = logging.Formatter('[%(asctime)s] %(levelname)-8s %(name)-12s %(message)s [in %(pathname)s:%(lineno)d]')

        # Create a console handler
        console_handler = logging.StreamHandler(sys.stdout)
        console_handler.setLevel(self.console_level)
        console_handler.setFormatter(formatter)

        self.logger.addHandler(console_handler)

        if self.log_file:
            """
            Create a file handler for file-based logging if a log file path is specified.

            This condition checks if a log file path (`self.log_file`) has been provided. If a log file path is provided,
            it indicates the intention to perform file-based logging in addition to console logging.
            """
            if not os.path.exists(self.log_file):
                # Create a file handler
                file_handler = FileHandler(filename=self.log_file)
                file_handler.setLevel(self.file_level)
                file_handler.setFormatter(formatter)
                # Add the file handler to the logger
                self.logger.addHandler(file_handler)
            else:
                print(f"Warning: Log file path '{self.log_file}' does not exist. File-based logging will be skipped.")
        else:
            """
            Skip file-based logging if no log file path is specified.

            If no log file path (`self.log_file`) is provided, this condition skips the creation of a file handler and
            ensures that only console-based logging will be performed.
            """
            pass


    def set_log_file(self, log_file):
        """
        Set the log file for file logging.

        Args:
            log_file (str): The path to the log file.
        """
        self.log_file = log_file
        self._init_logger()

    def debug(self, message):
        if not self.logger:
            self._init_logger()
        self.logger.debug(message)

    def info(self, message):
        if not self.logger:
            self._init_logger()
        self.logger.info(message)

    def warning(self, message):
        if not self.logger:
            self._init_logger()
        self.logger.warning(message)

    def error(self, message):
        if not self.logger:
            self._init_logger()
        self.logger.error(message)

    def critical(self, message):
        if not self.logger:
            self._init_logger()
        self.logger.critical(message)
